<!DOCTYPE html>
<html>
  <head>
    <title>cannon.js - sph demo</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="css/style.css" type="text/css"/>
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  </head>
  <body>
    <script src="../build/cannon.js"></script>
    <script src="../build/cannon.demo.js"></script>
    <script src="../libs/dat.gui.js"></script>
    <script src="../libs/Three.js"></script>
    <script src="../libs/TrackballControls.js"></script>
    <script src="../libs/Detector.js"></script>
    <script src="../libs/Stats.js"></script>
    <script src="../libs/smoothie.js"></script>
    <script>

      var demo = new CANNON.Demo();
      var nx=4, ny=4, nz=15, w=10, h=5, mass=0.01;
      var walls = true;


      // Test scalability - add scenes for different number of particles
      demo.addScene((nx*ny*nz)+ " particles", function(){

        // Create world
        var world = demo.getWorld();
        var sph = new CANNON.SPHSystem();
        sph.density = 1;
        sph.viscosity = 0.03;
        sph.smoothingRadius = 1.0;
        world.subsystems.push(sph);

        // Tweak contact properties.
        world.defaultContactMaterial.contactEquationStiffness = 1e11; // Contact stiffness - use to make softer/harder contacts
        world.defaultContactMaterial.contactEquationRelaxation = 2; // Stabilization time in number of timesteps

        // Max solver iterations: Use more for better force propagation, but keep in mind that it's not very computationally cheap!
        world.solver.iterations = 10;

        world.gravity.set(0,0,-10);

        // Materials
        var material = new CANNON.Material();
        var material_material = new CANNON.ContactMaterial(material, material, {
            friction: 0.06,
            restitution: 0.0
        });
        world.addContactMaterial(material_material);

        // ground plane
        var groundShape = new CANNON.Plane();
        var groundBody = new CANNON.Body({
            mass: 0,
            material: material
        });
        groundBody.addShape(groundShape);
        world.addBody(groundBody);
        demo.addVisual(groundBody);

        if(walls){

            // plane -x
            var planeShapeXmin = new CANNON.Plane();
            var planeXmin = new CANNON.Body({
                mass: 0,
                material: material
            });
            planeXmin.addShape(planeShapeXmin);
            planeXmin.quaternion.setFromAxisAngle(new CANNON.Vec3(0,1,0),Math.PI/2);
            planeXmin.position.set(-w*0.5,0,0);
            world.addBody(planeXmin);

            // Plane +x
            var planeShapeXmax = new CANNON.Plane();
            var planeXmax = new CANNON.Body({ mass: 0, material: material });
            planeXmax.addShape(planeShapeXmax);
            planeXmax.quaternion.setFromAxisAngle(new CANNON.Vec3(0,1,0),-Math.PI/2);
            planeXmax.position.set(w*0.5,0,0);
            world.addBody(planeXmax);

            // Plane -y
            var planeShapeYmin = new CANNON.Plane();
            var planeYmin = new CANNON.Body({ mass: 0, material: material });
            planeYmin.addShape(planeShapeYmin);
            planeYmin.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2);
            planeYmin.position.set(0,-h*0.5,0);
            world.addBody(planeYmin);

            // Plane +y
            var planeShapeYmax = new CANNON.Plane();
            var planeYmax = new CANNON.Body({ mass: 0, material: material });
            planeYmax.addShape(planeShapeYmax);
            planeYmax.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0), Math.PI/2);
            planeYmax.position.set(0,h*0.5,0);
            world.addBody(planeYmax);
        }

        // Create particles
        var rand = 0.1;
        for(var i=0; i!==nx; i++){
          for(var j=0; j!==ny; j++){
            for(var k=0; k!==nz; k++){
              var particle = new CANNON.Body({
                mass: mass,
                material: material
              });
              particle.addShape(new CANNON.Particle());
              particle.position.set((i + (Math.random()-0.5)*rand + 0.5)*w/nx - w*0.5,
                                    (j + (Math.random()-0.5)*rand + 0.5)*h/ny - h*0.5,
                                    k*h/ny);
              world.addBody(particle);
              sph.add(particle);
              demo.addVisual(particle);
            }
          }
        }
      });

      demo.start();

    </script>
  </body>
</html>
